using System;
using NSubstitute;
using Phoenix.ActionResults;
using Phoenix.Frames;
using Phoenix.Framework;
using Xunit;

namespace Phoenix.Tests
{
    public class GenericInvokeActionBuilderTests
    {
        public class StringActionNameOverloads
        {
            readonly InvokeActionBuilder<BuilderController> builder;
            readonly ControllerActionContext context;

            public StringActionNameOverloads()
            {
                context = PhoenixObjectMother.CreateContext(ControllerAction.CreateFrom("Home.Main"));
                builder = new InvokeActionBuilder<BuilderController>(context);
            }

            [Fact]
            public void builder_supports_string_actionnames()
            {
                builder.InvokeAction("Action").ActionInvoked(context, "BuilderController.Action");

                builder.InvokeActionCommand("Action").CommandInvokes(context, "BuilderController.Action");

                builder.InvokeActionWithResult<int>("Action").ActionInvokedWithResult<int>(context, "BuilderController.Action");
            }

            [Fact]
            public void builder_supports_string_actionnames_with_parameters()
            {
                builder.InvokeAction("Action", new object[]{1})
                    .ActionInvoked(context, "BuilderController.Action", parameters: new object[] { 1 });

                builder.InvokeActionCommand("Action", new object[] { 1 })
                    .CommandInvokes(context, "BuilderController.Action", parameters: new object[] { 1 });

                builder.InvokeActionWithResult<int>("Action", new object[] { 1 })
                    .ActionInvokedWithResult<int>(context, "BuilderController.Action", parameters: new object[] { 1 });
            }

            [Fact]
            public void builder_supports_string_actionnames_with_custom_frame()
            {
                var customFrame = Substitute.For<IContentFrame>();

                builder.InvokeAction(customFrame, "Action")
                    .ActionInvoked(context, "BuilderController.Action", customFrame);

                builder.InvokeActionCommand(customFrame, "Action")
                    .CommandInvokes(context, "BuilderController.Action", customFrame);

                builder.InvokeActionWithResult<int>(customFrame, "Action")
                    .ActionInvokedWithResult<int>(context, "BuilderController.Action", customFrame);
            }

            [Fact]
            public void builder_supports_string_actionnames_with_custom_frame_and_parameters()
            {
                var customFrame = Substitute.For<IContentFrame>();
                var parameters = new object[] { 1 };

                builder.InvokeAction(customFrame, "Action", parameters)
                    .ActionInvoked(context, "BuilderController.Action", customFrame, parameters: parameters);

                builder.InvokeActionCommand(customFrame, "Action", parameters)
                    .CommandInvokes(context, "BuilderController.Action", customFrame, parameters: parameters);

                builder.InvokeActionWithResult<int>(customFrame, "Action", parameters)
                    .ActionInvokedWithResult<int>(context, "BuilderController.Action", customFrame, parameters: parameters);
            }

            [Fact]
            public void builder_supports_string_actionnames_and_options()
            {
                builder.InvokeAction("Action", options: InvokeOptions.NoProgress)
                    .ActionInvoked(context, "BuilderController.Action", options: InvokeOptions.NoProgress);
                builder.InvokeActionCommand("Action", options: InvokeOptions.NoProgress)
                    .CommandInvokes(context, "BuilderController.Action", options: InvokeOptions.NoProgress);
                builder.InvokeActionWithResult<int>("Action", options: InvokeOptions.NoProgress)
                    .ActionInvokedWithResult<int>(context, "BuilderController.Action", options: InvokeOptions.NoProgress);
            }

            [Fact]
            public void builder_supports_string_actionnames_with_parameters_and_options()
            {
                var parameters = new object[] {1};
                builder.InvokeAction("Action", parameters, InvokeOptions.NoProgress)
                    .ActionInvoked(context, "BuilderController.Action", parameters: parameters, options: InvokeOptions.NoProgress);

                builder.InvokeActionCommand("Action", parameters, InvokeOptions.NoProgress)
                    .CommandInvokes(context, "BuilderController.Action", parameters: parameters, options: InvokeOptions.NoProgress);

                builder.InvokeActionWithResult<int>("Action", parameters, InvokeOptions.NoProgress)
                    .ActionInvokedWithResult<int>(context, "BuilderController.Action", parameters: parameters, options: InvokeOptions.NoProgress);
            }

            [Fact]
            public void builder_supports_string_actionnames_with_custom_frame_and_options()
            {
                var customFrame = Substitute.For<IContentFrame>();

                builder.InvokeAction(customFrame, "Action", options: InvokeOptions.NoProgress)
                    .ActionInvoked(context, "BuilderController.Action", customFrame, options: InvokeOptions.NoProgress);

                builder.InvokeActionCommand(customFrame, "Action", options: InvokeOptions.NoProgress)
                    .CommandInvokes(context, "BuilderController.Action", customFrame, options: InvokeOptions.NoProgress);

                builder.InvokeActionWithResult<int>(customFrame, "Action", options: InvokeOptions.NoProgress)
                    .ActionInvokedWithResult<int>(context, "BuilderController.Action", customFrame, options: InvokeOptions.NoProgress);
            }

            [Fact]
            public void builder_supports_string_actionnames_with_custom_frame_and_parameters_and_options()
            {
                var customFrame = Substitute.For<IContentFrame>();

                var parameters = new object[] {1};
                builder.InvokeAction(customFrame, "Action", parameters: parameters, options: InvokeOptions.NoProgress)
                    .ActionInvoked(context, "BuilderController.Action", customFrame, parameters: parameters, options: InvokeOptions.NoProgress);

                builder.InvokeActionCommand(customFrame, "Action", parameters, options: InvokeOptions.NoProgress)
                    .CommandInvokes(context, "BuilderController.Action", customFrame, parameters: parameters, options: InvokeOptions.NoProgress);

                builder.InvokeActionWithResult<int>(customFrame, "Action", parameters, options: InvokeOptions.NoProgress)
                    .ActionInvokedWithResult<int>(context, "BuilderController.Action", customFrame, parameters: parameters, options: InvokeOptions.NoProgress);
            }
        }

        public class ExpressionsReturningActionResults
        {
            readonly InvokeActionBuilder<BuilderController> builder;
            readonly ControllerActionContext context;

            public ExpressionsReturningActionResults()
            {
                context = PhoenixObjectMother.CreateContext(ControllerAction.CreateFrom("Home.Main"));
                builder = new InvokeActionBuilder<BuilderController>(context);
            }

            [Fact]
            public void builder_supports_expression_returning_actionresult()
            {
                builder.InvokeAction(c=>c.Action()).ActionInvoked(context, "BuilderController.Action");
                builder.InvokeActionCommand(c => c.Action()).CommandInvokes(context, "BuilderController.Action");
                builder.InvokeActionCommand<int>((c, commandArg) => c.Action(commandArg))
                    .CommandInvokes(context, "BuilderController.Action", commandArgument: 5, parameters:new object[]{5});
                builder.InvokeActionWithResult<int>(c => c.Action()).ActionInvokedWithResult<int>(context, "BuilderController.Action");
            }

            [Fact]
            public void builder_supports_expression_returning_actionresult_with_parameters()
            {
                builder.InvokeAction(c => c.Action(1)).ActionInvoked(context, "BuilderController.Action", parameters: new object[] { 1 });
                builder.InvokeActionCommand(c => c.Action(1)).CommandInvokes(context, "BuilderController.Action", parameters: new object[] { 1 });
                builder.InvokeActionCommand<int>((c, commandArg) => c.Action(1, commandArg))
                    .CommandInvokes(context, "BuilderController.Action", commandArgument: 5, parameters: new object[] { 1, 5 });
                builder.InvokeActionWithResult<int>(c => c.Action(1)).ActionInvokedWithResult<int>(context, "BuilderController.Action", parameters: new object[] { 1 });
            }

            [Fact]
            public void builder_supports_expression_returning_actionresult_with_custom_frame()
            {
                var customFrame = Substitute.For<IContentFrame>();

                builder.InvokeAction(customFrame, c => c.Action()).ActionInvoked(context, "BuilderController.Action", customFrame);
                builder.InvokeActionCommand(customFrame, c => c.Action()).CommandInvokes(context, "BuilderController.Action", customFrame);
                builder.InvokeActionCommand<int>(customFrame, (c, commandArg) => c.Action(commandArg))
                    .CommandInvokes(context, "BuilderController.Action", commandArgument: 5, parameters: new object[] { 5 });
                builder.InvokeActionWithResult<int>(customFrame, c => c.Action()).ActionInvokedWithResult<int>(context, "BuilderController.Action", customFrame);
            }

            [Fact]
            public void builder_supports_expression_returning_actionresult_with_custom_frame_and_parameters()
            {
                var customFrame = Substitute.For<IContentFrame>();

                builder.InvokeAction(customFrame, c => c.Action(1))
                    .ActionInvoked(context, "BuilderController.Action", customFrame, parameters: new object[] { 1 });

                builder.InvokeActionCommand(customFrame, c => c.Action(1))
                    .CommandInvokes(context, "BuilderController.Action", customFrame, parameters: new object[] { 1 });

                builder.InvokeActionCommand<int>(customFrame, (c, commandArg) => c.Action(1, commandArg))
                    .CommandInvokes(context, "BuilderController.Action", commandArgument: 5, parameters: new object[] { 1, 5 });

                builder.InvokeActionWithResult<int>(customFrame, c => c.Action(1))
                    .ActionInvokedWithResult<int>(context, "BuilderController.Action", customFrame, parameters: new object[] { 1 });
            }

            [Fact]
            public void builder_supports_expression_returning_actionresult_and_options()
            {
                builder.InvokeAction(c => c.Action(), InvokeOptions.NoProgress)
                    .ActionInvoked(context, "BuilderController.Action", options: InvokeOptions.NoProgress);

                builder.InvokeActionCommand(c => c.Action(), options: InvokeOptions.NoProgress)
                    .CommandInvokes(context, "BuilderController.Action", options: InvokeOptions.NoProgress);

                builder.InvokeActionCommand<int>((c, commandArg) => c.Action(commandArg), options: InvokeOptions.NoProgress)
                    .CommandInvokes(context, "BuilderController.Action", commandArgument: 5, parameters: new object[] { 5 }, options: InvokeOptions.NoProgress);

                builder.InvokeActionWithResult<int>(c => c.Action(), InvokeOptions.NoProgress)
                    .ActionInvokedWithResult<int>(context, "BuilderController.Action", options: InvokeOptions.NoProgress);
            }

            [Fact]
            public void builder_supports_expression_returning_actionresult_with_parameters_and_options()
            {
                builder.InvokeAction(c => c.Action(1), options: InvokeOptions.NoProgress)
                    .ActionInvoked(context, "BuilderController.Action", parameters: new object[] { 1 }, options: InvokeOptions.NoProgress);

                builder.InvokeActionCommand(c => c.Action(1), options: InvokeOptions.NoProgress)
                    .CommandInvokes(context, "BuilderController.Action", parameters: new object[] { 1 }, options: InvokeOptions.NoProgress);

                builder.InvokeActionCommand<int>((c, commandArg) => c.Action(1, commandArg), options: InvokeOptions.NoProgress)
                    .CommandInvokes(context, "BuilderController.Action", commandArgument: 5, parameters: new object[] { 1, 5 }, options: InvokeOptions.NoProgress);

                builder.InvokeActionWithResult<int>(c => c.Action(1), options: InvokeOptions.NoProgress)
                    .ActionInvokedWithResult<int>(context, "BuilderController.Action", parameters: new object[] { 1 }, options: InvokeOptions.NoProgress);
            }

            [Fact]
            public void builder_supports_expression_returning_actionresult_with_custom_frame_and_options()
            {
                var customFrame = Substitute.For<IContentFrame>();

                builder.InvokeAction(customFrame, c => c.Action(), options: InvokeOptions.NoProgress)
                    .ActionInvoked(context, "BuilderController.Action", customFrame, options: InvokeOptions.NoProgress);

                builder.InvokeActionCommand(customFrame, c => c.Action(), options: InvokeOptions.NoProgress)
                    .CommandInvokes(context, "BuilderController.Action", customFrame, options: InvokeOptions.NoProgress);

                builder.InvokeActionCommand<int>(customFrame, (c, commandArg) => c.Action(commandArg), options: InvokeOptions.NoProgress)
                    .CommandInvokes(context, "BuilderController.Action", commandArgument: 5, parameters: new object[] { 5 }, options: InvokeOptions.NoProgress);

                builder.InvokeActionWithResult<int>(customFrame, c => c.Action(), options: InvokeOptions.NoProgress)
                    .ActionInvokedWithResult<int>(context, "BuilderController.Action", customFrame, options: InvokeOptions.NoProgress);
            }

            [Fact]
            public void builder_supports_expression_returning_actionresult_with_custom_frame_and_parameters_and_options()
            {
                var customFrame = Substitute.For<IContentFrame>();

                builder.InvokeAction(customFrame, c => c.Action(1), options: InvokeOptions.NoProgress)
                    .ActionInvoked(context, "BuilderController.Action", customFrame, parameters: new object[] { 1 }, options: InvokeOptions.NoProgress);

                builder.InvokeActionCommand(customFrame, c => c.Action(1), options: InvokeOptions.NoProgress)
                    .CommandInvokes(context, "BuilderController.Action", customFrame, parameters: new object[] { 1 }, options: InvokeOptions.NoProgress);

                builder.InvokeActionCommand<int>(customFrame, (c, commandArg) => c.Action(1, commandArg), options: InvokeOptions.NoProgress)
                    .CommandInvokes(context, "BuilderController.Action", commandArgument: 5, parameters: new object[] { 1, 5 }, options: InvokeOptions.NoProgress);

                builder.InvokeActionWithResult<int>(customFrame, c => c.Action(1), options: InvokeOptions.NoProgress)
                    .ActionInvokedWithResult<int>(context, "BuilderController.Action", customFrame, parameters: new object[] { 1 }, options: InvokeOptions.NoProgress);
            }
        }

        public class ExpressionsReturningDerrivedActionResults
        {
            readonly InvokeActionBuilder<BuilderController> builder;
            readonly ControllerActionContext context;

            public ExpressionsReturningDerrivedActionResults()
            {
                context = PhoenixObjectMother.CreateContext(ControllerAction.CreateFrom("Home.Main"));
                builder = new InvokeActionBuilder<BuilderController>(context);
            }

            [Fact]
            public void builder_supports_expression_returning_actionresult()
            {
                builder.InvokeAction(c => c.PageAction()).ActionInvoked(context, "BuilderController.PageAction");
                builder.InvokeActionCommand(c => c.PageAction()).CommandInvokes(context, "BuilderController.PageAction");
                builder.InvokeActionCommand<int>((c, commandArg) => c.PageAction(commandArg))
                    .CommandInvokes(context, "BuilderController.PageAction", commandArgument: 5, parameters: new object[] { 5 });
                builder.InvokeActionWithResult<int>(c => c.PageAction()).ActionInvokedWithResult<int>(context, "BuilderController.PageAction");
            }

            [Fact]
            public void builder_supports_expression_returning_actionresult_with_parameters()
            {
                builder.InvokeAction(c => c.PageAction(1)).ActionInvoked(context, "BuilderController.PageAction", parameters: new object[] { 1 });
                builder.InvokeActionCommand(c => c.PageAction(1)).CommandInvokes(context, "BuilderController.PageAction", parameters: new object[] { 1 });
                builder.InvokeActionCommand<int>((c, commandArg) => c.PageAction(1, commandArg))
                    .CommandInvokes(context, "BuilderController.PageAction", commandArgument: 5, parameters: new object[] { 1, 5 });
                builder.InvokeActionWithResult<int>(c => c.PageAction(1)).ActionInvokedWithResult<int>(context, "BuilderController.PageAction", parameters: new object[] { 1 });
            }

            [Fact]
            public void builder_supports_expression_returning_actionresult_with_custom_frame()
            {
                var customFrame = Substitute.For<IContentFrame>();

                builder.InvokeAction(customFrame, c => c.PageAction()).ActionInvoked(context, "BuilderController.PageAction", customFrame);
                builder.InvokeActionCommand(customFrame, c => c.PageAction()).CommandInvokes(context, "BuilderController.PageAction", customFrame);
                builder.InvokeActionCommand<int>(customFrame, (c, commandArg) => c.PageAction(commandArg))
                    .CommandInvokes(context, "BuilderController.PageAction", commandArgument: 5, parameters: new object[] { 5 });
                builder.InvokeActionWithResult<int>(customFrame, c => c.PageAction()).ActionInvokedWithResult<int>(context, "BuilderController.PageAction", customFrame);
            }

            [Fact]
            public void builder_supports_expression_returning_actionresult_with_custom_frame_and_parameters()
            {
                var customFrame = Substitute.For<IContentFrame>();

                builder.InvokeAction(customFrame, c => c.PageAction(1))
                    .ActionInvoked(context, "BuilderController.PageAction", customFrame, parameters: new object[] { 1 });

                builder.InvokeActionCommand(customFrame, c => c.PageAction(1))
                    .CommandInvokes(context, "BuilderController.PageAction", customFrame, parameters: new object[] { 1 });

                builder.InvokeActionCommand<PageActionResult, int>(customFrame, (c, commandArg) => c.PageAction(1, commandArg))
                    .CommandInvokes(context, "BuilderController.PageAction", customFrame, commandArgument: 5, parameters: new object[] { 1, 5 });

                builder.InvokeActionWithResult<PageActionResult, int>(customFrame, c => c.PageAction(1))
                    .ActionInvokedWithResult<int>(context, "BuilderController.PageAction", customFrame, parameters: new object[] { 1 });
            }

            [Fact]
            public void builder_supports_expression_returning_actionresult_and_options()
            {
                builder.InvokeAction(c => c.PageAction(), options: InvokeOptions.NoProgress)
                    .ActionInvoked(context, "BuilderController.PageAction", options: InvokeOptions.NoProgress);

                builder.InvokeActionCommand(c => c.PageAction(), options: InvokeOptions.NoProgress)
                    .CommandInvokes(context, "BuilderController.PageAction", options: InvokeOptions.NoProgress);

                builder.InvokeActionCommand<int>((c, commandArg) => c.PageAction(commandArg), options: InvokeOptions.NoProgress)
                    .CommandInvokes(context, "BuilderController.PageAction", commandArgument: 5, parameters: new object[] { 5 }, 
                                    options: InvokeOptions.NoProgress);

                builder.InvokeActionWithResult<int>(c => c.PageAction(), options: InvokeOptions.NoProgress)
                    .ActionInvokedWithResult<int>(context, "BuilderController.PageAction", options: InvokeOptions.NoProgress);
            }

            [Fact]
            public void builder_supports_expression_returning_actionresult_with_parameters_and_options()
            {
                builder.InvokeAction(c => c.PageAction(1), options: InvokeOptions.NoProgress)
                    .ActionInvoked(context, "BuilderController.PageAction", parameters: new object[] { 1 }, options: InvokeOptions.NoProgress);

                builder.InvokeActionCommand(c => c.PageAction(1), options: InvokeOptions.NoProgress)
                    .CommandInvokes(context, "BuilderController.PageAction", parameters: new object[] { 1 }, options: InvokeOptions.NoProgress);

                builder.InvokeActionCommand<int>((c, commandArg) => c.PageAction(1, commandArg), options: InvokeOptions.NoProgress)
                    .CommandInvokes(context, "BuilderController.PageAction", commandArgument: 5, parameters: new object[] { 1, 5 }, options: InvokeOptions.NoProgress);

                builder.InvokeActionWithResult<int>(c => c.PageAction(1), options: InvokeOptions.NoProgress)
                    .ActionInvokedWithResult<int>(context, "BuilderController.PageAction", parameters: new object[] { 1 }, options: InvokeOptions.NoProgress);
            }

            [Fact]
            public void builder_supports_expression_returning_actionresult_with_custom_frame_and_options()
            {
                var customFrame = Substitute.For<IContentFrame>();

                builder.InvokeAction(customFrame, c => c.PageAction(), options: InvokeOptions.NoProgress)
                    .ActionInvoked(context, "BuilderController.PageAction", customFrame, options: InvokeOptions.NoProgress);

                builder.InvokeActionCommand(customFrame, c => c.PageAction(), options: InvokeOptions.NoProgress)
                    .CommandInvokes(context, "BuilderController.PageAction", customFrame, options: InvokeOptions.NoProgress);

                builder.InvokeActionCommand<int>(customFrame, (c, commandArg) => c.PageAction(commandArg), options: InvokeOptions.NoProgress)
                    .CommandInvokes(context, "BuilderController.PageAction", commandArgument: 5, parameters: new object[] { 5 }, options: InvokeOptions.NoProgress);

                builder.InvokeActionWithResult<int>(customFrame, c => c.PageAction(), options: InvokeOptions.NoProgress)
                    .ActionInvokedWithResult<int>(context, "BuilderController.PageAction", customFrame, options: InvokeOptions.NoProgress);
            }

            [Fact]
            public void builder_supports_expression_returning_actionresult_with_custom_frame_and_parameters_and_options()
            {
                var customFrame = Substitute.For<IContentFrame>();

                builder.InvokeAction(customFrame, c => c.PageAction(1), options: InvokeOptions.NoProgress)
                    .ActionInvoked(context, "BuilderController.PageAction", customFrame, parameters: new object[] { 1 }, options: InvokeOptions.NoProgress);

                builder.InvokeActionCommand(customFrame, c => c.PageAction(1), options: InvokeOptions.NoProgress)
                    .CommandInvokes(context, "BuilderController.PageAction", customFrame, parameters: new object[] { 1 }, options: InvokeOptions.NoProgress);

                builder.InvokeActionCommand<PageActionResult, int>(customFrame, (c, commandArg) => c.PageAction(1, commandArg), options: InvokeOptions.NoProgress)
                    .CommandInvokes(context, "BuilderController.PageAction", customFrame, commandArgument: 5, 
                                    parameters: new object[] { 1, 5 }, options: InvokeOptions.NoProgress);

                builder.InvokeActionWithResult<PageActionResult, int>(customFrame, c => c.PageAction(1), options: InvokeOptions.NoProgress)
                    .ActionInvokedWithResult<int>(context, "BuilderController.PageAction", customFrame, 
                                                  parameters: new object[] { 1 }, options: InvokeOptions.NoProgress);
            }
        }

        public class ExpressionsReturningTaskOfActionResults
        {
            readonly InvokeActionBuilder<BuilderController> builder;
            readonly ControllerActionContext context;

            public ExpressionsReturningTaskOfActionResults()
            {
                context = PhoenixObjectMother.CreateContext(ControllerAction.CreateFrom("Home.Main"));
                builder = new InvokeActionBuilder<BuilderController>(context);
            }

            [Fact]
            public void builder_supports_expression_returning_actionresult()
            {
                builder.InvokeAction(c => c.ActionAsync()).ActionInvoked(context, "BuilderController.ActionAsync");
                builder.InvokeActionCommand(c => c.ActionAsync()).CommandInvokes(context, "BuilderController.ActionAsync");
                builder.InvokeActionCommand<int>((c, commandArgs) => c.ActionAsync(commandArgs)).CommandInvokes(context, "BuilderController.ActionAsync", parameters:new object[]{ 5 }, commandArgument: 5);
                builder.InvokeActionWithResult<int>(c => c.ActionAsync()).ActionInvokedWithResult<int>(context, "BuilderController.ActionAsync");
            }

            [Fact]
            public void builder_supports_expression_returning_actionresult_with_parameters()
            {
                builder.InvokeAction(c => c.ActionAsync(1)).ActionInvoked(context, "BuilderController.ActionAsync", parameters: new object[] { 1 });
                builder.InvokeActionCommand(c => c.ActionAsync(1)).CommandInvokes(context, "BuilderController.ActionAsync", parameters: new object[] { 1 });
                builder.InvokeActionCommand<int>((c, commandArgs) => c.ActionAsync(1, commandArgs))
                    .CommandInvokes(context, "BuilderController.ActionAsync", parameters: new object[] { 1, 5 }, commandArgument: 5);
                builder.InvokeActionWithResult<int>(c => c.ActionAsync(1)).ActionInvokedWithResult<int>(context, "BuilderController.ActionAsync", parameters: new object[] { 1 });
            }

            [Fact]
            public void builder_supports_expression_returning_actionresult_with_custom_frame()
            {
                var customFrame = Substitute.For<IContentFrame>();

                builder.InvokeAction(customFrame, c => c.ActionAsync()).ActionInvoked(context, "BuilderController.ActionAsync", customFrame);
                builder.InvokeActionCommand(customFrame, c => c.ActionAsync()).CommandInvokes(context, "BuilderController.ActionAsync", customFrame);
                builder.InvokeActionCommand<int>(customFrame, (c, commandArgs) => c.ActionAsync(commandArgs))
                    .CommandInvokes(context, "BuilderController.ActionAsync", parameters: new object[] { 5 }, commandArgument: 5);
                builder.InvokeActionWithResult<int>(customFrame, c => c.ActionAsync()).ActionInvokedWithResult<int>(context, "BuilderController.ActionAsync", customFrame);
            }

            [Fact]
            public void builder_supports_expression_returning_actionresult_with_custom_frame_and_parameters()
            {
                var customFrame = Substitute.For<IContentFrame>();

                builder.InvokeAction(customFrame, c => c.ActionAsync(1))
                    .ActionInvoked(context, "BuilderController.ActionAsync", customFrame, parameters: new object[] { 1 });

                builder.InvokeActionCommand(customFrame, c => c.ActionAsync(1))
                    .CommandInvokes(context, "BuilderController.ActionAsync", customFrame, parameters: new object[] { 1 });

                builder.InvokeActionCommand<int>(customFrame, (c, commandArgs) => c.ActionAsync(1, commandArgs))
                    .CommandInvokes(context, "BuilderController.ActionAsync", parameters: new object[] { 1, 5 }, commandArgument: 5);

                builder.InvokeActionWithResult<int>(customFrame, c => c.ActionAsync(1))
                    .ActionInvokedWithResult<int>(context, "BuilderController.ActionAsync", customFrame, parameters: new object[] { 1 });
            }

            [Fact]
            public void builder_supports_expression_returning_actionresult_and_options()
            {
                builder.InvokeAction(c => c.ActionAsync(), options: InvokeOptions.NoProgress)
                    .ActionInvoked(context, "BuilderController.ActionAsync", options: InvokeOptions.NoProgress);

                builder.InvokeActionCommand(c => c.ActionAsync(), options: InvokeOptions.NoProgress)
                    .CommandInvokes(context, "BuilderController.ActionAsync", options: InvokeOptions.NoProgress);

                builder.InvokeActionCommand<int>((c, commandArgs) => c.ActionAsync(commandArgs), options: InvokeOptions.NoProgress)
                    .CommandInvokes(context, "BuilderController.ActionAsync", parameters: new object[] { 5 }, commandArgument: 5, options: InvokeOptions.NoProgress);

                builder.InvokeActionWithResult<int>(c => c.ActionAsync(), options: InvokeOptions.NoProgress)
                    .ActionInvokedWithResult<int>(context, "BuilderController.ActionAsync", options: InvokeOptions.NoProgress);
            }

            [Fact]
            public void builder_supports_expression_returning_actionresult_with_parameters_and_options()
            {
                builder.InvokeAction(c => c.ActionAsync(1), options: InvokeOptions.NoProgress)
                    .ActionInvoked(context, "BuilderController.ActionAsync", parameters: new object[] { 1 }, options: InvokeOptions.NoProgress);

                builder.InvokeActionCommand(c => c.ActionAsync(1), options: InvokeOptions.NoProgress)
                    .CommandInvokes(context, "BuilderController.ActionAsync", parameters: new object[] { 1 }, options: InvokeOptions.NoProgress);

                builder.InvokeActionCommand<int>((c, commandArgs) => c.ActionAsync(1, commandArgs), options: InvokeOptions.NoProgress)
                    .CommandInvokes(context, "BuilderController.ActionAsync", parameters: new object[] { 1, 5 }, commandArgument: 5, options: InvokeOptions.NoProgress);

                builder.InvokeActionWithResult<int>(c => c.ActionAsync(1), options: InvokeOptions.NoProgress)
                    .ActionInvokedWithResult<int>(context, "BuilderController.ActionAsync", parameters: new object[] { 1 }, options: InvokeOptions.NoProgress);
            }

            [Fact]
            public void builder_supports_expression_returning_actionresult_with_custom_frame_and_options()
            {
                var customFrame = Substitute.For<IContentFrame>();

                builder.InvokeAction(customFrame, c => c.ActionAsync(), options: InvokeOptions.NoProgress)
                    .ActionInvoked(context, "BuilderController.ActionAsync", customFrame, options: InvokeOptions.NoProgress);

                builder.InvokeActionCommand(customFrame, c => c.ActionAsync(), options: InvokeOptions.NoProgress)
                    .CommandInvokes(context, "BuilderController.ActionAsync", customFrame, options: InvokeOptions.NoProgress);

                builder.InvokeActionCommand<int>(customFrame, (c, commandArgs) => c.ActionAsync(commandArgs), options: InvokeOptions.NoProgress)
                    .CommandInvokes(context, "BuilderController.ActionAsync", parameters: new object[] { 5 }, commandArgument: 5, options: InvokeOptions.NoProgress);

                builder.InvokeActionWithResult<int>(customFrame, c => c.ActionAsync(), options: InvokeOptions.NoProgress)
                    .ActionInvokedWithResult<int>(context, "BuilderController.ActionAsync", customFrame, options: InvokeOptions.NoProgress);
            }

            [Fact]
            public void builder_supports_expression_returning_actionresult_with_custom_frame_and_parameters_and_options()
            {
                var customFrame = Substitute.For<IContentFrame>();

                builder.InvokeAction(customFrame, c => c.ActionAsync(1), options: InvokeOptions.NoProgress)
                    .ActionInvoked(context, "BuilderController.ActionAsync", customFrame, parameters: new object[] { 1 }, options: InvokeOptions.NoProgress);

                builder.InvokeActionCommand(customFrame, c => c.ActionAsync(1), options: InvokeOptions.NoProgress)
                    .CommandInvokes(context, "BuilderController.ActionAsync", customFrame, parameters: new object[] { 1 }, options: InvokeOptions.NoProgress);

                builder.InvokeActionCommand<int>(customFrame, (c, commandArgs) => c.ActionAsync(1, commandArgs), options: InvokeOptions.NoProgress)
                    .CommandInvokes(context, "BuilderController.ActionAsync", parameters: new object[] { 1, 5 }, commandArgument: 5, options: InvokeOptions.NoProgress);

                builder.InvokeActionWithResult<int>(customFrame, c => c.ActionAsync(1), options: InvokeOptions.NoProgress)
                    .ActionInvokedWithResult<int>(context, "BuilderController.ActionAsync", customFrame, parameters: new object[] { 1 }, options: InvokeOptions.NoProgress);
            }
        }

        public class ExpressionsReturningTaskOfPageActionResults
        {
            readonly InvokeActionBuilder<BuilderController> builder;
            readonly ControllerActionContext context;

            public ExpressionsReturningTaskOfPageActionResults()
            {
                context = PhoenixObjectMother.CreateContext(ControllerAction.CreateFrom("Home.Main"));
                builder = new InvokeActionBuilder<BuilderController>(context);
            }

            [Fact]
            public void builder_supports_expression_returning_actionresult()
            {
                builder.InvokeAction(c => c.PageActionAsync())
                    .ActionInvoked(context, "BuilderController.PageActionAsync");

                builder.InvokeActionCommand(c => c.PageActionAsync())
                    .CommandInvokes(context, "BuilderController.PageActionAsync");

                builder.InvokeActionCommand<PageActionResult, int>((c, commandArgs) => c.PageActionAsync(commandArgs))
                    .CommandInvokes(context, "BuilderController.PageActionAsync", parameters: new object[] { 5 }, commandArgument: 5);

                builder.InvokeActionWithResult<PageActionResult, int>(c => c.PageActionAsync())
                    .ActionInvokedWithResult<int>(context, "BuilderController.PageActionAsync");
            }

            [Fact]
            public void builder_supports_expression_returning_actionresult_with_parameters()
            {
                builder.InvokeAction(c => c.PageActionAsync(1)).ActionInvoked(context, "BuilderController.PageActionAsync", parameters: new object[] { 1 });

                builder.InvokeActionCommand(c => c.PageActionAsync(1)).CommandInvokes(context, "BuilderController.PageActionAsync", parameters: new object[] { 1 });

                builder.InvokeActionCommand<PageActionResult, int>((c, commandArgs) => c.PageActionAsync(1, commandArgs))
                    .CommandInvokes(context, "BuilderController.PageActionAsync", parameters: new object[] { 1, 5 }, commandArgument: 5);

                builder.InvokeActionWithResult<PageActionResult, int>(c => c.PageActionAsync(1))
                    .ActionInvokedWithResult<int>(context, "BuilderController.PageActionAsync", parameters: new object[] { 1 });
            }

            [Fact]
            public void builder_supports_expression_returning_actionresult_with_custom_frame()
            {
                var customFrame = Substitute.For<IContentFrame>();

                builder.InvokeAction(customFrame, c => c.PageActionAsync())
                    .ActionInvoked(context, "BuilderController.PageActionAsync", customFrame);

                builder.InvokeActionCommand(customFrame, c => c.PageActionAsync())
                    .CommandInvokes(context, "BuilderController.PageActionAsync", customFrame);

                builder.InvokeActionCommand<PageActionResult, int>(customFrame, (c, commandArgs) => c.PageActionAsync(commandArgs))
                    .CommandInvokes(context, "BuilderController.PageActionAsync", parameters: new object[] { 5 }, commandArgument: 5);

                builder.InvokeActionWithResult<PageActionResult, int>(customFrame, c => c.PageActionAsync())
                    .ActionInvokedWithResult<int>(context, "BuilderController.PageActionAsync", customFrame);
            }

            [Fact]
            public void builder_supports_expression_returning_actionresult_with_custom_frame_and_parameters()
            {
                var customFrame = Substitute.For<IContentFrame>();

                builder.InvokeAction(customFrame, c => c.PageActionAsync(1))
                    .ActionInvoked(context, "BuilderController.PageActionAsync", customFrame, parameters: new object[] { 1 });

                builder.InvokeActionCommand(customFrame, c => c.PageActionAsync(1))
                    .CommandInvokes(context, "BuilderController.PageActionAsync", customFrame, parameters: new object[] { 1 });

                builder.InvokeActionCommand<PageActionResult, int>(customFrame, (c, commandArgs) => c.PageActionAsync(1, commandArgs))
                    .CommandInvokes(context, "BuilderController.PageActionAsync", parameters: new object[] { 1, 5 }, commandArgument: 5);

                builder.InvokeActionWithResult<PageActionResult, int>(customFrame, c => c.PageActionAsync(1))
                    .ActionInvokedWithResult<int>(context, "BuilderController.PageActionAsync", customFrame, parameters: new object[] { 1 });
            }

            [Fact]
            public void builder_supports_expression_returning_actionresult_and_options()
            {
                builder.InvokeAction(c => c.PageActionAsync(), options: InvokeOptions.NoProgress)
                    .ActionInvoked(context, "BuilderController.PageActionAsync", options: InvokeOptions.NoProgress);

                builder.InvokeActionCommand(c => c.PageActionAsync(), options: InvokeOptions.NoProgress)
                    .CommandInvokes(context, "BuilderController.PageActionAsync", options: InvokeOptions.NoProgress);

                builder.InvokeActionCommand<PageActionResult, int>((c, commandArgs) => c.PageActionAsync(commandArgs), options: InvokeOptions.NoProgress)
                    .CommandInvokes(context, "BuilderController.PageActionAsync", parameters: new object[] { 5 }, commandArgument: 5, options: InvokeOptions.NoProgress);

                builder.InvokeActionWithResult<PageActionResult, int>(c => c.PageActionAsync(), options: InvokeOptions.NoProgress)
                    .ActionInvokedWithResult<int>(context, "BuilderController.PageActionAsync", options: InvokeOptions.NoProgress);
            }

            [Fact]
            public void builder_supports_expression_returning_actionresult_with_parameters_and_options()
            {
                builder.InvokeAction(c => c.PageActionAsync(1), options: InvokeOptions.NoProgress)
                    .ActionInvoked(context, "BuilderController.PageActionAsync", parameters: new object[] { 1 }, options: InvokeOptions.NoProgress);

                builder.InvokeActionCommand(c => c.PageActionAsync(1), options: InvokeOptions.NoProgress)
                    .CommandInvokes(context, "BuilderController.PageActionAsync", parameters: new object[] { 1 }, options: InvokeOptions.NoProgress);

                builder.InvokeActionCommand<PageActionResult, int>((c, commandArgs) => c.PageActionAsync(1, commandArgs), options: InvokeOptions.NoProgress)
                    .CommandInvokes(context, "BuilderController.PageActionAsync", parameters: new object[] { 1, 5 }, commandArgument: 5, options: InvokeOptions.NoProgress);

                builder.InvokeActionWithResult<PageActionResult, int>(c => c.PageActionAsync(1), options: InvokeOptions.NoProgress)
                    .ActionInvokedWithResult<int>(context, "BuilderController.PageActionAsync", parameters: new object[] { 1 }, options: InvokeOptions.NoProgress);
            }

            [Fact]
            public void builder_supports_expression_returning_actionresult_with_custom_frame_and_options()
            {
                var customFrame = Substitute.For<IContentFrame>();

                builder.InvokeAction(customFrame, c => c.PageActionAsync(), options: InvokeOptions.NoProgress)
                    .ActionInvoked(context, "BuilderController.PageActionAsync", customFrame, options: InvokeOptions.NoProgress);

                builder.InvokeActionCommand(customFrame, c => c.PageActionAsync(), options: InvokeOptions.NoProgress)
                    .CommandInvokes(context, "BuilderController.PageActionAsync", customFrame, options: InvokeOptions.NoProgress);

                builder.InvokeActionCommand<PageActionResult, int>(customFrame, (c, commandArgs) => c.PageActionAsync(commandArgs), options: InvokeOptions.NoProgress)
                    .CommandInvokes(context, "BuilderController.PageActionAsync", parameters: new object[] { 5 }, commandArgument: 5, options: InvokeOptions.NoProgress);

                builder.InvokeActionWithResult<PageActionResult, int>(customFrame, c => c.PageActionAsync(), options: InvokeOptions.NoProgress)
                    .ActionInvokedWithResult<int>(context, "BuilderController.PageActionAsync", customFrame, options: InvokeOptions.NoProgress);
            }

            [Fact]
            public void builder_supports_expression_returning_actionresult_with_custom_frame_and_parameters_and_options()
            {
                var customFrame = Substitute.For<IContentFrame>();

                builder.InvokeAction(customFrame, c => c.PageActionAsync(1), options: InvokeOptions.NoProgress)
                    .ActionInvoked(context, "BuilderController.PageActionAsync", customFrame,
                                   parameters: new object[] { 1 }, options: InvokeOptions.NoProgress);

                builder.InvokeActionCommand(customFrame, c => c.PageActionAsync(1), options: InvokeOptions.NoProgress)
                    .CommandInvokes(context, "BuilderController.PageActionAsync", customFrame, 
                                    parameters: new object[] { 1 }, options: InvokeOptions.NoProgress);

                builder.InvokeActionCommand<PageActionResult, int>(customFrame, (c, commandArgs) => c.PageActionAsync(1, commandArgs), options: InvokeOptions.NoProgress)
                    .CommandInvokes(context, "BuilderController.PageActionAsync", parameters: new object[] { 1, 5 },
                                    commandArgument: 5, options: InvokeOptions.NoProgress);

                builder.InvokeActionWithResult<PageActionResult, int>(customFrame, c => c.PageActionAsync(1), options: InvokeOptions.NoProgress)
                    .ActionInvokedWithResult<int>(context, "BuilderController.PageActionAsync", customFrame, 
                                                  parameters: new object[] { 1 }, options: InvokeOptions.NoProgress);
            }
        }
    }
}